#include "utils/time_val.h"
#include <iomanip>
#include <sstream>
#include <string.h>
#include <stdio.h>

#include <time.h>
#if (defined WIN32)
#include <windows.h>
#else
#include <sys/time.h>
#include <sys/times.h>
#endif

using std::setfill;
using std::setw;
using std::string;
using std::stringstream;

namespace cox {
	long long deltaMs = 0;

	TimeVal::TimeVal(long long s, long long ms, long long us) : s(s), ms(ms), us(us) {
		/* @初始化秒、毫秒、微秒值，当毫秒、微秒数值>1000时进位，当毫秒、微秒数值<0时借位 */
		if (this->us >= 1000) {
			this->ms += this->us / 1000;
			this->us %= 1000;
		} else if (this->us < 0) {
			this->ms -= 1;
			this->us += 1000;
		} else {
			/* do nothing */
		}
		if (this->ms >= 1000) {
			this->s += this->ms / 1000;
			this->ms %= 1000;
		} else if (this->ms < 0) {
			this->s -= 1;
			this->ms += 1000;
		} else {
		}
	}

	// TimeVal对象，将时间转换为毫秒
	long long TimeVal::toMs(void) const {
		/* @将秒、毫秒、微秒转换为毫秒数值并返回 */
		return s * 1000 + ms + (us > 0 ? 1 : 0);
	}

	bool operator<(const TimeVal &tv1, const TimeVal &tv2) {
		if (tv1.s < tv2.s) {
			return true;
		}
		if (tv1.s == tv2.s) {
			if (tv1.ms < tv2.ms) {
				return true;
			}
			if (tv1.ms == tv2.ms) {
				return tv1.us < tv2.us;
			}
		}
		return false;
	}

	bool operator<=(const TimeVal &tv1, const TimeVal &tv2) {
		/* @比较tv1是否小于等于tv2 */
		return tv1 == tv2 || tv1 < tv2;
	}

	bool operator<(const TimeVal &tv, const long long ms) {
		/* @比较tv转换为毫秒后数值是否小于ms */
		return tv < TimeVal(ms / 1000, ms % 1000);
	}

	// TimeVal对象比较函数，是否大于其他TimeVal对象
	bool operator>(const TimeVal &tv1, const TimeVal &tv2) {
		/* @比较tv1是否大于tv2 */
		if (tv1.s > tv2.s) {
			return true;
		}
		if (tv1.s == tv2.s) {
			if (tv1.ms > tv2.ms) {
				return true;
			}
			if (tv1.ms == tv2.ms) {
				return tv1.us > tv2.us;
			}
		}
		return false;
	}

	bool operator>=(const TimeVal &tv1, const TimeVal &tv2) {
		/* @比较tv1是否大于等于tv2 */
		return tv1 == tv2 || tv1 > tv2;
	}

	bool operator>(const TimeVal &tv, const long long ms) {
		/* @比较tv转换为毫秒后数值是否大于ms */
		return tv > TimeVal(ms / 1000, ms % 1000);
	}

	bool operator==(const TimeVal &tv1, const TimeVal &tv2) {
		/* @比较tv1是否等于tv2 */
		return tv1.s == tv2.s && tv1.ms == tv2.ms && tv1.us == tv2.us;
	}

	// 设置时间偏移
	void SetDeltaMs(long long ms) {
		/* @设置时间偏移 */
		deltaMs = ms;
	}

#if (defined WIN32) || (defined __CYGWIN32___)
	TimeVal GetTime(bool withDeltaMs) {
		FILETIME ft;
		GetSystemTimeAsFileTime(&ft);
		ULARGE_INTEGER uli;
		uli.LowPart           = ft.dwLowDateTime;
		uli.HighPart          = ft.dwHighDateTime;
		ULONGLONG currentTime = uli.QuadPart;
		currentTime           = (currentTime - 116444736000000000) / 10000;
		if (withDeltaMs) {
			currentTime += deltaMs;
		}
		TimeVal tv;
		tv.s  = currentTime / 1000;
		tv.ms = currentTime % 1000;
		tv.us = 0;
		return tv;
	}

	long long GetTick(void) { return GetTickCount(); }

	TimeVal GetMoNoTime() {
		long long ticks = GetTickCount();
		TimeVal   tv;
		tv.s  = ticks / 1000;
		tv.ms = ticks % 1000;
		tv.us = 0;
		return tv;
	}

#else /* Linux */
	TimeVal GetTime(bool withDeltaMs) {
		struct timeval tv;
		(void) gettimeofday(&tv, NULL);
		if (withDeltaMs && deltaMs != 0) {
			long long ms = tv.tv_sec * 1000 + tv.tv_usec / 1000 + deltaMs;
			return TimeVal(ms / 1000, ms % 1000, tv.tv_usec % 1000);
		}
		return TimeVal(tv.tv_sec, tv.tv_usec / 1000, tv.tv_usec % 1000);
	}

	long long GetTick(void) {
		long long tick = times(nullptr);
		return tick;
	}

	TimeVal GetMoNoTime() {
		struct timespec tv;
		clock_gettime(CLOCK_MONOTONIC, &tv);
		return TimeVal(tv.tv_sec, tv.tv_nsec / 1000000, tv.tv_nsec / 1000);
	}

#endif /* 结束跨平台区分 */
	long long GetTimeMs(bool withDeltaMs) { return GetTime(withDeltaMs).toMs(); }

	TimeVal operator+(const TimeVal &tv1, const TimeVal &tv2) {
		// 依次相加两个对象的秒数、毫秒数和微秒数，根据结果新建时间对象并返回
		return TimeVal(tv1.s + tv2.s, tv1.ms + tv2.ms, tv1.us + tv2.us);
	}

	TimeVal operator+(const TimeVal &tv, const long long &ms) {
		/* @tv的毫秒数增加ms，根据结果新建时间对象并返回 */
		return TimeVal(tv.s, tv.ms + ms, tv.us);
	}

	TimeVal operator-(const TimeVal &tv1, const TimeVal &tv2) {
		/* @依次相减两个对象的秒数、毫秒数和微秒数，根据结果新建时间对象并返回 */
		return TimeVal(tv1.s - tv2.s, tv1.ms - tv2.ms, tv1.us - tv2.us);
	}

	TimeVal operator-(const TimeVal &tv, const long long &ms) {
		/* @tv的毫秒数减去ms，根据结果新建时间对象并返回 */
		return TimeVal(tv.s, tv.ms - ms, tv.us);
	}
} // namespace cox
